﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace OS
{
    public class ProcessControlBlock
    {
        public int time;                            //the time the process has ran for
        public int maxTime;                         //the max time the process can run
        public int lines;                           //the lines the process has print
        public int maxLines;                        //the max number of lines the process can print
        public string groupID;                      //the group id of the process
        public string register_R;
        public bool toggle_C;
        public int register_IC;
        public string register_IR;
        public int register_SI;
        public int register_PI;
        public int register_TI;
        public int register_PTR;
        public char f;
        public List<int> p;
        public List<int> d;
        public int frames;                          //the number of frames the process currently has
        public int maxFrames;                       //the max number of frames the process can have
        public String terminationType;              //how the process terminated
        public List<int> tracksOfOutput;            //a list containing all of the track IDs with output
        public Dictionary<int, Object> TLB;         //TLB for this process
        public bool fetchFault;                     //boolean value for if a page fault occured in the fetch step
        public bool prepForPrint;
        public List<int> tracksToRelease;
        public int printLines;
        public int dataLines;

        /// <summary>
        /// Default constructor
        /// </summary>
        public ProcessControlBlock()
        {
            time = 0;
            register_R = "    ";
            toggle_C = false;
            register_IC = 0;
            register_IR = null;
            register_SI = 0;
            register_PI = 0;
            register_TI = 0;
            register_PTR = -1;
            p = new List<int>();
            d = new List<int>();
            frames = 0;
            maxFrames = 4;
            terminationType = "";
            tracksOfOutput = new List<int>();
            TLB = new Dictionary<int, object>();
            fetchFault = false;
            prepForPrint = false;
            tracksToRelease = new List<int>();
            printLines = 0;
            dataLines = 0;
        }

        /// <summary>
        /// Creates a new ProcessControlBlock from a given one
        /// </summary>
        /// <param name="p"></param>
        public ProcessControlBlock(ProcessControlBlock p)
        {
            this.time = p.time;
            this.register_R = p.register_R;
            this.toggle_C = p.toggle_C;
            this.register_IC = p.register_IC;
            this.register_IR = p.register_IR;
            this.register_SI = p.register_SI;
            this.register_PI = p.register_PI;
            this.register_TI = p.register_TI;
            this.register_PTR = p.register_PTR;
            this.p = p.p;
            this.d = p.d;
            this.maxTime = p.maxTime;
            this.lines = p.lines;
            this.maxLines = p.maxLines;
            this.groupID = p.groupID;
            this.f = p.f;
            this.frames = p.frames;
            this.maxFrames = p.maxFrames;
            this.terminationType = p.terminationType;
            this.tracksOfOutput = p.tracksOfOutput;
            this.TLB = p.TLB;
            this.fetchFault = p.fetchFault;
            this.prepForPrint = p.prepForPrint;
            this.tracksToRelease = p.tracksToRelease;
            this.printLines = p.printLines;
            this.dataLines = p.dataLines;
        }

        /// <summary>
        /// Transfers the registers from the CPU to the PCB
        /// </summary>
        public void GetRegistersFromCPU()
        {
            this.register_R = CPU.accumulator_R;
            this.toggle_C = CPU.toggle_C;
            this.register_IC = CPU.instructionCounter_IC;
            this.register_IR = CPU.instructionRegister_IR;
            this.register_SI = CPU.SI;
            this.register_PI = CPU.PI;
            this.register_TI = CPU.TI;
            this.register_PTR = CPU.PTR_Register;

            Trace.WriteToTrace("Registers transferred from CPU to PCB");
        }

        /// <summary>
        /// Transfers the registers from the PCB to the CPU
        /// </summary>
        public void StoreRegistersToCPU()
        {
            CPU.accumulator_R = this.register_R;
            CPU.toggle_C = this.toggle_C;
            CPU.instructionCounter_IC = this.register_IC;
            CPU.instructionRegister_IR = this.register_IR;
            CPU.SI = this.register_SI;
            CPU.PI = this.register_PI;
            CPU.TI = this.register_TI;
            CPU.PTR_Register = this.register_PTR;
            Trace.WriteToTrace("Registers transferred from PCB to CPU");
        }

        /// <summary>
        /// Gets if the p list is empty
        /// </summary>
        /// <returns>A boolean value for if the d list is empty or not</returns>
        public bool IsPEmpty()
        {
            return this.p.Count == 0;
        }

        /// <summary>
        /// Gets if the d list is empty
        /// </summary>
        /// <returns>A boolean value for if the d list is empty or not</returns>
        public bool IsDEmpty()
        {
            return this.d.Count == 0;
        }

        public void ClearInterrupts()
        {
            this.register_SI = 0;
            this.register_TI = 0;
            this.register_PI = 0;
        }
    }
}
